/******************************************************************************
 * Copyright (c) 2024 Fabian Schiebel.
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of LICENSE.txt.
 *
 * Contributors:
 *     Fabian Schiebel and others
 *****************************************************************************/

#ifndef PHASAR_PHASARLLVM_CONTROLFLOW_GLOBALCTORSDTORSMODEL_H
#define PHASAR_PHASARLLVM_CONTROLFLOW_GLOBALCTORSDTORSMODEL_H

#include "llvm/ADT/ArrayRef.h"
#include "llvm/IR/Function.h"

namespace psr {
class LLVMProjectIRDB;

/// \brief  Provides utilities to inject a function into the IR under analysis
/// that captures global constructors and destructors as described in the 2021
/// Paper "Modeling the Effects of Global Variables in Data-Flow Analysis for
/// C/C++" by Schubert et al.
///
/// See <10.1109/SCAM52516.2021.00010> for more information.
class GlobalCtorsDtorsModel {
public:
  static constexpr llvm::StringLiteral ModelName =
      "__psrCRuntimeGlobalCtorsModel";

  static constexpr llvm::StringLiteral DtorModelName =
      "__psrCRuntimeGlobalDtorsModel";

  static constexpr llvm::StringLiteral DtorsCallerName =
      "__psrGlobalDtorsCaller";

  static constexpr llvm::StringLiteral UserEntrySelectorName =
      "__psrCRuntimeUserEntrySelector";

  /// @brief Function that creates a new global model and inserts it into the
  /// IRDB. The returned function is the global model that was inserted.
  /// @param[in, out] IRDB IR database that will have the global model
  /// inserted.
  /// @param[in] UserEntryPoints Entry points for the program given as
  /// llvm::Function pointers. You usually want to pass here the main function
  static llvm::Function *
  buildModel(LLVMProjectIRDB &IRDB,
             llvm::ArrayRef<llvm::Function *> UserEntryPoints);

  /// @brief Function that creates a new global model and inserts it into the
  /// IRDB. The returned function is the global model that was inserted.
  /// @param[in, out] IRDB IR database that will have the global model
  /// inserted.
  /// @param[in] UserEntryPoints Entry points for the program given as
  /// std::strings. You usually want to pass here the main function
  static llvm::Function *
  buildModel(LLVMProjectIRDB &IRDB,
             llvm::ArrayRef<std::string> UserEntryPoints);

  /// Returns true, if a function was generated by the GlobalCtorsDtorsModel.
  [[nodiscard]] static bool isPhasarGenerated(const llvm::Function &F) noexcept;
};
} // namespace psr

#endif // PHASAR_PHASARLLVM_CONTROLFLOW_GLOBALCTORSDTORSMODEL_H
